001 /** 002 * Copyright 2003-2004 The Apache Software Foundation 003 * Copyright 2005 Stephen McConnell 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package net.dpml.cli.util; 018 019 import java.util.Comparator; 020 import java.util.List; 021 022 import net.dpml.cli.Group; 023 import net.dpml.cli.Option; 024 import net.dpml.cli.option.Command; 025 import net.dpml.cli.option.DefaultOption; 026 import net.dpml.cli.option.Switch; 027 028 /** 029 * A collection of Comparators suitable for use with Option instances. 030 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a> 031 * @version 1.0.0 032 */ 033 public final class Comparators 034 { 035 private Comparators() 036 { 037 // static 038 } 039 040 /** 041 * Chains comparators together. 042 * 043 * @see #chain(Comparator[]) 044 * @param c0 a comparator 045 * @param c1 a comparator 046 * @return a chained comparator 047 */ 048 public static Comparator chain( final Comparator c0, final Comparator c1 ) 049 { 050 return chain( new Comparator[]{c0, c1} ); 051 } 052 053 /** 054 * Chains comparators together. 055 * 056 * @see #chain(Comparator[]) 057 * @param c0 a comparator 058 * @param c1 a comparator 059 * @param c2 a comparator 060 * @return a chained comparator 061 */ 062 public static Comparator chain( final Comparator c0, final Comparator c1, final Comparator c2 ) 063 { 064 return chain( new Comparator[]{c0, c1, c2} ); 065 } 066 067 /** 068 * Chains comparators together. 069 * 070 * @see #chain(Comparator[]) 071 * @param c0 a comparator 072 * @param c1 a comparator 073 * @param c2 a comparator 074 * @param c3 a comparator 075 * @return a chained comparator 076 */ 077 public static Comparator chain( 078 final Comparator c0, final Comparator c1, final Comparator c2, final Comparator c3 ) 079 { 080 return chain( new Comparator[]{c0, c1, c2, c3} ); 081 } 082 083 /** 084 * Chains comparators together. 085 * 086 * @see #chain(Comparator[]) 087 * @param c0 a comparator 088 * @param c1 a comparator 089 * @param c2 a comparator 090 * @param c3 a comparator 091 * @param c4 a comparator 092 * @return a chained comparator 093 */ 094 public static Comparator chain( 095 final Comparator c0, final Comparator c1, final Comparator c2, 096 final Comparator c3, final Comparator c4 ) 097 { 098 return chain( new Comparator[]{c0, c1, c2, c3, c4} ); 099 } 100 101 /** 102 * Chains comparators together. 103 * 104 * @see #chain(Comparator[]) 105 * @param comparators a List of comparators to chain together 106 * @return a chained comparator 107 */ 108 public static Comparator chain( final List comparators ) 109 { 110 return new Chain( 111 (Comparator[]) comparators.toArray( 112 new Comparator[ comparators.size() ] ) ); 113 } 114 115 /** 116 * Chains an array of comparators together. Each Comparator will be called 117 * in turn until one of them return a non-zero value, this value will be 118 * returned. 119 * 120 * @param comparators the array of comparators 121 * @return a chained comparator 122 */ 123 public static Comparator chain( final Comparator[] comparators ) 124 { 125 return new Chain( comparators ); 126 } 127 128 /** 129 * Chains a series of Comparators together. 130 */ 131 private static class Chain implements Comparator 132 { 133 private final Comparator[] m_chain; 134 135 /** 136 * Creates a Comparator chain using the specified array of Comparators 137 * @param chain the Comparators in the chain 138 */ 139 public Chain( final Comparator[] chain ) 140 { 141 m_chain = new Comparator[ chain.length ]; 142 System.arraycopy( chain, 0, m_chain, 0, chain.length ); 143 } 144 145 /** 146 * Compare two values. 147 * @param left the first value 148 * @param right the second value 149 * @return the result 150 */ 151 public int compare( final Object left, final Object right ) 152 { 153 int result = 0; 154 for( int i = 0; result == 0 && i < m_chain.length; ++i ) 155 { 156 result = m_chain[i].compare( left, right ); 157 } 158 return result; 159 } 160 } 161 162 /** 163 * Reverses a comparator's logic. 164 * 165 * @param wrapped 166 * the Comparator to reverse the logic of 167 * @return a comparator with reverse logic 168 */ 169 private static Comparator reverse( final Comparator wrapped ) 170 { 171 return new Reverse( wrapped ); 172 } 173 174 /** 175 * A reverse comparator. 176 */ 177 private static class Reverse implements Comparator 178 { 179 private final Comparator m_wrapped; 180 181 /** 182 * Creates a Comparator with reverse logic 183 * @param wrapped the original logic 184 */ 185 public Reverse( final Comparator wrapped ) 186 { 187 m_wrapped = wrapped; 188 } 189 190 /** 191 * Compare two values. 192 * @param left the first value 193 * @param right the second value 194 * @return the result 195 */ 196 public int compare( final Object left, final Object right ) 197 { 198 return -m_wrapped.compare( left, right ); 199 } 200 } 201 202 /** 203 * Forces Group instances to appear at the beginning of lists 204 * 205 * @see Group 206 * @return a new comparator 207 */ 208 public static Comparator groupFirst() 209 { 210 return new GroupFirst(); 211 } 212 213 /** 214 * Forces Group instances to appear at the end of lists 215 * 216 * @see Group 217 * @return a new comparator 218 */ 219 public static Comparator groupLast() 220 { 221 return reverse( groupFirst() ); 222 } 223 224 /** 225 * A group first comparator. 226 */ 227 private static class GroupFirst implements Comparator 228 { 229 /** 230 * Compare two values. 231 * @param left the first value 232 * @param right the second value 233 * @return the result 234 */ 235 public int compare( final Object left, final Object right ) 236 { 237 final boolean l = left instanceof Group; 238 final boolean r = right instanceof Group; 239 240 if( l ^ r ) 241 { 242 if( l ) 243 { 244 return -1; 245 } 246 return 1; 247 } 248 return 0; 249 } 250 } 251 252 /** 253 * Forces Switch instances to appear at the beginning of lists 254 * 255 * @see Switch 256 * @return a new comparator 257 */ 258 public static Comparator switchFirst() 259 { 260 return new SwitchFirst(); 261 } 262 263 /** 264 * Forces Switch instances to appear at the end of lists 265 * 266 * @see Switch 267 * @return a new comparator 268 */ 269 public static Comparator switchLast() 270 { 271 return reverse( switchFirst() ); 272 } 273 274 /** 275 * A switch first comparator. 276 */ 277 private static class SwitchFirst implements Comparator 278 { 279 /** 280 * Compare two values. 281 * @param left the first value 282 * @param right the second value 283 * @return the result 284 */ 285 public int compare( final Object left, final Object right ) 286 { 287 final boolean l = left instanceof Switch; 288 final boolean r = right instanceof Switch; 289 290 if( l ^ r ) 291 { 292 if( l ) 293 { 294 return -1; 295 } 296 return 1; 297 } 298 return 0; 299 } 300 } 301 302 /** 303 * Forces Command instances to appear at the beginning of lists 304 * 305 * @see Command 306 * @return a new comparator 307 */ 308 public static Comparator commandFirst() 309 { 310 return new CommandFirst(); 311 } 312 313 /** 314 * Forces Command instances to appear at the end of lists 315 * 316 * @see Command 317 * @return a new comparator 318 */ 319 public static Comparator commandLast() 320 { 321 return reverse( commandFirst() ); 322 } 323 324 /** 325 * A command first comparator. 326 */ 327 private static class CommandFirst implements Comparator 328 { 329 /** 330 * Compare two values. 331 * @param left the first value 332 * @param right the second value 333 * @return the result 334 */ 335 public int compare( final Object left, final Object right ) 336 { 337 final boolean l = left instanceof Command; 338 final boolean r = right instanceof Command; 339 340 if( l ^ r ) 341 { 342 if( l ) 343 { 344 return -1; 345 } 346 return 1; 347 } 348 return 0; 349 } 350 } 351 352 /** 353 * Forces DefaultOption instances to appear at the beginning of lists 354 * 355 * @see DefaultOption 356 * @return a new comparator 357 */ 358 public static Comparator defaultOptionFirst() 359 { 360 return new DefaultOptionFirst(); 361 } 362 363 /** 364 * Forces DefaultOption instances to appear at the end of lists 365 * 366 * @see DefaultOption 367 * @return a new comparator 368 */ 369 public static Comparator defaultOptionLast() 370 { 371 return reverse( defaultOptionFirst() ); 372 } 373 374 /** 375 * An option first comparator. 376 */ 377 private static class DefaultOptionFirst implements Comparator 378 { 379 /** 380 * Compare two values. 381 * @param left the first value 382 * @param right the second value 383 * @return the result 384 */ 385 public int compare( final Object left, final Object right ) 386 { 387 final boolean l = left instanceof DefaultOption; 388 final boolean r = right instanceof DefaultOption; 389 390 if( l ^ r ) 391 { 392 if( l ) 393 { 394 return -1; 395 } 396 return 1; 397 } 398 return 0; 399 } 400 } 401 402 /** 403 * Forces Comparators with a particular trigger to appear at the beginning 404 * of lists 405 * 406 * @param name 407 * the trigger name to select 408 * @see Option#getTriggers() 409 * @return a new comparator 410 */ 411 public static Comparator namedFirst( final String name ) 412 { 413 return new Named( name ); 414 } 415 416 /** 417 * Forces Comparators with a particular trigger to appear at the end of 418 * lists 419 * 420 * @param name 421 * the trigger name to select 422 * @see Option#getTriggers() 423 * @return a new comparator 424 */ 425 public static Comparator namedLast( final String name ) 426 { 427 return reverse( new Named( name ) ); 428 } 429 430 /** 431 * A named comparator. 432 */ 433 private static class Named implements Comparator 434 { 435 private final String m_name; 436 437 /** 438 * Creates a Comparator that sorts a particular name high in order 439 * @param name the trigger name to select 440 */ 441 public Named( final String name ) 442 { 443 m_name = name; 444 } 445 446 /** 447 * Compare two values. 448 * @param primary the first value 449 * @param secondary the second value 450 * @return the result 451 */ 452 public int compare( final Object primary, final Object secondary ) 453 { 454 final Option left = (Option) primary; 455 final Option right = (Option) secondary; 456 457 final boolean l = left.getTriggers().contains( m_name ); 458 final boolean r = right.getTriggers().contains( m_name ); 459 460 if( l ^ r ) 461 { 462 if( l ) 463 { 464 return -1; 465 } 466 return 1; 467 } 468 return 0; 469 } 470 } 471 472 /** 473 * Orders Options by preferredName 474 * 475 * @see Option#getPreferredName() 476 * @return a new comparator 477 */ 478 public static Comparator preferredNameFirst() 479 { 480 return new PreferredName(); 481 } 482 483 /** 484 * Orders Options by preferredName, reversed 485 * 486 * @see Option#getPreferredName() 487 * @return a new comparator 488 */ 489 public static Comparator preferredNameLast() 490 { 491 return reverse( preferredNameFirst() ); 492 } 493 494 /** 495 * A preferred name comparator. 496 */ 497 private static class PreferredName implements Comparator 498 { 499 /** 500 * Compare two values. 501 * @param primary the first value 502 * @param secondary the second value 503 * @return the result 504 */ 505 public int compare( final Object primary, final Object secondary ) 506 { 507 final Option left = (Option) primary; 508 final Option right = (Option) secondary; 509 return left.getPreferredName().compareTo( right.getPreferredName() ); 510 } 511 } 512 513 /** 514 * Orders Options grouping required Options first 515 * 516 * @see Option#isRequired() 517 * @return a new comparator 518 */ 519 public static Comparator requiredFirst() 520 { 521 return new Required(); 522 } 523 524 /** 525 * Orders Options grouping required Options last 526 * 527 * @see Option#isRequired() 528 * @return a new comparator 529 */ 530 public static Comparator requiredLast() 531 { 532 return reverse( requiredFirst() ); 533 } 534 535 /** 536 * A required comparator. 537 */ 538 private static class Required implements Comparator 539 { 540 /** 541 * Compare two values. 542 * @param primary the first value 543 * @param secondary the second value 544 * @return the result 545 */ 546 public int compare( final Object primary, final Object secondary ) 547 { 548 final Option left = (Option) primary; 549 final Option right = (Option) secondary; 550 551 final boolean l = left.isRequired(); 552 final boolean r = right.isRequired(); 553 554 if( l ^ r ) 555 { 556 if( l ) 557 { 558 return -1; 559 } 560 return 1; 561 } 562 return 0; 563 } 564 } 565 }